package com.wmzdq.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;
import javax.xml.registry.infomodel.Organization;

import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
import org.springframework.orm.hibernate5.SessionFactoryUtils;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.transaction.annotation.Transactional;

//数据库相关功能
@Configuration
//@PropertySource({"classpath:/config/appConfig.properties"})
//开启事务
@EnableTransactionManagement(proxyTargetClass=true)
//@Import({DaoSourceConfig.class})
@ComponentScan(basePackages={"com.wmzdq.common","com.wmzdq.test.common","com.wmzdq.framework.db.hibernate.dao","com.wmzdq.framework.db.hibernate.service"},useDefaultFilters=false,includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION,value={Service.class,Transactional.class,Repository.class})})
public class DaoConfig implements TransactionManagementConfigurer {
    
    @Autowired
    DataSource datasource;
    
    //要想使用properties中的
    //@Value("${master.jdbc.driver}")
    //private String persistence;
    //@Autowired
    //Environment ent;
    
    //必须要有，否则datasourceConfig 无法解析properties，需要研究一下
    @Bean  
    public static PropertySourcesPlaceholderConfigurer placehodlerConfigurer() {  
        PropertySourcesPlaceholderConfigurer config= new PropertySourcesPlaceholderConfigurer();
       // config.setOrder(0);
       // config.setIgnoreUnresolvablePlaceholders(true);
        //Resource resource=new ClassPathResource("classpath:config/dataSource.properties");
        //config.setLocation(resource);
        return config;
    }
    
  //加载数据库地址等
    @Configuration
    //自动扫描
    @MapperScan(basePackages={"com.wmzdq.mybatis.mapper"},sqlSessionFactoryRef="sqlSessionFactory")
    @PropertySource({"classpath:/config/dataSource.properties","classpath:/config/appConfig.properties"})
    static class DaoSourceConfig
    {
        @Value("${master.jdbc.driver}")
        private String driverClass;
        
        @Value("${master.jdbc.url}")
        private String url;
        
        @Value("${master.jdbc.username}")
        private String username;
        
        @Value("${master.jdbc.password}")
        private String password;
        
        @Bean(name="dataSource",destroyMethod="close")
        public DataSource dataSource(){
            BasicDataSource dataSource=new BasicDataSource();
            dataSource.setDriverClassName(driverClass);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            dataSource.setMaxWait(1000);
            dataSource.setMaxActive(100);
            dataSource.setMaxIdle(50);
            dataSource.setMinIdle(20);
            dataSource.setInitialSize(20);
            dataSource.setTestOnBorrow(true);
            dataSource.setValidationQuery("select 1");
            dataSource.setTimeBetweenEvictionRunsMillis(300000);
            dataSource.setMinEvictableIdleTimeMillis(360000);
            dataSource.setRemoveAbandoned(true);
            dataSource.setLogAbandoned(false);
            return dataSource;
            
        }
        
        public String[] anntionPackages(){
            List<String> list=new ArrayList<String>();
            list.add("com/wmzdq/framework/db/hibernate/dto");
            list.addAll(extraPackages());
            String[] str=new String[list.size()];
            
            return list.toArray(str);
        }
        
        //额外的hibernate package包
        public List<String> extraPackages(){
            return new ArrayList<String>();
        }

        
//        @Bean(name="hibernateSessionFactory")
//        public SessionFactory hiberSessionFactory(DataSource datasource){
//            LocalSessionFactoryBuilder builder=new LocalSessionFactoryBuilder(datasource);
//            //实体类 所在的包，和scanPackages()方法不同，后者应该是扫描 configuation类的
//            builder.scanPackages(anntionPackages());
//            Properties properties=new Properties();
//            //hibernate方言
//            properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
//            //打印sql
//            properties.put("hibernate.show_sql", "true");
//            //properties.put("connection.characterEncoding", "gbk");
//            //格式化sql
//            properties.put("hibernate.format_sql", "true");
//            //不启用hibernate缓存
//            properties.put("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
//            //jdbc.fetch_size是指Hibernate每次从数据库中取出并放到JDBC的Statement中的记录条数。Fetch Size设的越大，读数据库的次数越少，速度越快，Fetch Size越小，读数据库的次数越多，速度越慢
//            properties.put("hibernate.jdbc.fetch_size","50");
//            /*其实这个hibernate.hbm2ddl.auto参数的作用主要用于：自动创建|更新|验证数据库表结构。如果不是此方面的需求建议set value="none"。
//                create：
//                每次加载hibernate时都会删除上一次的生成的表，然后根据你的model类再重新来生成新表，哪怕两次没有任何改变也要这样执行，这就是导致数据库表数据丢失的一个重要原因。
//                create-drop ：
//                每次加载hibernate时根据model类生成表，但是sessionFactory一关闭,表就自动删除。
//                update：
//                最常用的属性，第一次加载hibernate时根据model类会自动建立起表的结构（前提是先建立好数据库），以后加载hibernate时根据 model类自动更新表结构，即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后，表结构是不会被马上建立起来的，是要等 应用第一次运行起来后才会。
//                validate ：
//                每次加载hibernate时，验证创建数据库表结构，只会和数据库中的表进行比较，不会创建新表，但是会插入新值。*/
//            properties.put("hibernate.hbm2ddl.auto","none");
//            
//            properties.put("hibernate.current_session_context_class","thread");
//            builder.setProperties(properties);
//            builder.configure();
//            return builder.buildSessionFactory();
//        }
        
      //不要使用自动注入datasource，会导致循环引用
        @Bean(name="sqlSessionFactory")
        public SqlSessionFactoryBean factoryBean(/*DataSource dataSource,*/Environment ent) throws IOException{
            SqlSessionFactoryBean bean=new SqlSessionFactoryBean();
            bean.setDataSource(dataSource());
            System.out.print(ent.getProperty("persistence"));
            //把通配符转成实际的resource数组
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/config/sqlmap/*.xml"));
            bean.setConfigLocation(new ClassPathResource("/config/mybatis-config.xml"));
            return bean;
        }
        
    }
    

    
    
    //自动注入 datasource，无需声明
   /* @Resource(name="dataSource",type=DataSource.class)
    public DataSource dataSource;*/
    
    
    //自动扫描，注册成实现类
   /* @Bean
    public MapperScannerConfigurer scannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer=new MapperScannerConfigurer();
        //自动扫描的包名
        mapperScannerConfigurer.setBasePackage("com.wmzdq.mybatis.mapper");
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        return mapperScannerConfigurer;
        
    }*/
    
    
    
    @Bean(name="transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager manager=new DataSourceTransactionManager();
        manager.setDataSource(dataSource);
        //manager.
        return manager;
    }
    
    /*@Bean(name="hibernateTransactionManager")
    public HibernateTransactionManager hibernateTransactionManager(DataSource dataSource,SessionFactory hibernateSessionFactory){
        HibernateTransactionManager manager=new HibernateTransactionManager();
        manager.setDataSource(dataSource);
        manager.setSessionFactory(hibernateSessionFactory);
        //manager.
        return manager;
    }*/

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager()
    {
        // TODO Auto-generated method stub
        return transactionManager(datasource);
    }
}
